<?php
/**
 * App首页数据
 * Author: lyun
 * Date: 2018/11/14
 * Created by Panxsoft.
 */

namespace App\Http\Services\Api\V1\App\Webview;

use App\Models\Banners\BannerImage;
use App\Models\Currency;
use App\Models\Extension\Extension;
use App\Models\Layout\LayoutModule;
use App\Models\Layout\LayoutRoute;
use App\Models\Layout\Module;
use App\Models\Press\Press;
use App\Models\Products\Product;
use App\Services\Customers\AppCustomer;
use App\Services\MobileApp\AppEnv;
use App\Services\Repositories\ProductRepository;
use App\Services\Utils\ApiChecker;
use App\Services\Utils\ImageHelper;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;

class HomeService
{
    use ApiChecker;

    /**
     * @param $layout_route
     * @return LayoutModule[]|Collection
     * @throws \Exception
     */
    public function getAppHomeSetting($layout_route)
    {
        /** @var LayoutRoute $layout_route */
        $layout_route = (new LayoutRoute)
            ->where('route', $layout_route)
            ->where('store_id', AppEnv::storeId())
            ->latest('layout_route_id')
            ->first();
        $this->checkItemExist($layout_route);

        /** @var Collection|LayoutModule[] $layout_modules */
        $layout_modules = (new LayoutModule)
            ->where('layout_id', $layout_route->layout_id)
            ->where('position', LayoutModule::POSITION_CONTENT_TOP)
            ->oldest('sort_order')
            ->get();

        $layout_modules->load('module');

        $modules = $this->transformLayoutModules($layout_modules);

        return $modules;
    }

    /**
     * @param Collection $layout_modules
     * @return Collection
     */
    private function transformLayoutModules(Collection $layout_modules)
    {
        $layout_modules = $layout_modules->filter(function (LayoutModule $layout_module) {

            // 验证模块的状态(0,1)
            $status = $layout_module->module->setting['status'] ?? Module::MODULE_STATUS_OFF;
            $status || $layout_module->code = null;

            switch ($layout_module->code) {
                case Extension::CODE_SLIDE_SHOW : // app首页轮播图
                    $this->assembleBanner($layout_module);
                    break;
                case Extension::CODE_LATEST : // app首页最新商品
                    $this->assembleLatestProduct($layout_module);
                    break;
                case Extension::CODE_BANNER :  // app首页横幅
                    $this->assembleBanner($layout_module);
                    break;
                case Extension::CODE_FEATURED :  // app首页推荐商品
                    $this->assembleRecommendProduct($layout_module);
                    break;
                case Extension::CODE_PANX_APP_ICON_LINK: // app首页自定义区块
                    $this->assembleAppBlock($layout_module);
                    break;
                case Extension::CODE_SPECIAL : // app首页特价商品
                    $this->assembleSpecialProduct($layout_module);
                    break;
                case Extension::CODE_PRESS_LATEST : // app首页最新新闻
                    $this->assemblePress($layout_module);
                    break;
                case Extension::CODE_BESTSELLER :  // app首页热销商品
                    $this->assembleBestSellerProduct($layout_module);
                    break;
                default:
                    $layout_module->setting = null;
            }

            $layout_module->addHidden('module');

            return $status;
        })
            ->values();

        return $layout_modules;
    }

    /**
     * @param $layout_module
     * @return mixed
     */
    private function assembleBanner(LayoutModule $layout_module)
    {
        $slide_show_module = $layout_module->module;

        $slide_show_setting = $slide_show_module->setting;

        $slide_show_setting['banner_images'] = (new BannerImage)
            ->filterBannerStatus($slide_show_setting['banner_id'])
            ->where('language_id', AppEnv::languageId())
//            ->where('banner_id', $slide_show_setting['banner_id'])
            ->oldest('sort_order')
            ->get();

        $layout_module->setting = $slide_show_setting;

        return $layout_module;
    }

    /**
     * @param $layout_module
     * @return mixed
     * @throws \Exception
     */
    private function assembleLatestProduct(LayoutModule $layout_module)
    {
        /** @var Module $latest_product_module */
        $latest_product_module = $layout_module->module;

        $latest_product_setting = $latest_product_module->setting;

        $latest_product_setting['latest_products'] = $this->getLatestProduct($latest_product_setting['limit']);

        $layout_module->setting = $latest_product_setting;

        return $layout_module;
    }

    /**
     * @param LayoutModule $layout_module
     *
     * @return mixed
     * @throws \Exception
     */
    private function assembleRecommendProduct(LayoutModule $layout_module)
    {
        $recommend_product_module = $layout_module->module;

        $setting = $recommend_product_module->setting;

        $setting['recommend_products'] = $this->getRecommendProduct($setting['product'], $setting['limit']);

        $layout_module->setting = $setting;

        return $layout_module;
    }

    /**
     * @param $layout_module
     * @return mixed
     * @throws \Exception
     */
    private function assembleSpecialProduct(LayoutModule $layout_module)
    {
        $special_product_module = $layout_module->module;

        $special_product_setting = $special_product_module->setting;

        $special_product_setting['special_products'] = $this->getSpecialProduct($special_product_setting['limit']);

        $layout_module->setting = $special_product_setting;

        return $layout_module;
    }

    /**
     * @param $layout_module
     * @return mixed
     * @throws \Exception
     */
    private function assembleBestSellerProduct($layout_module)
    {
        $best_seller_product_module = $layout_module->module;

        $best_seller_product_setting = $best_seller_product_module->setting;

        $best_seller_product_setting['best_seller_products'] = $this->getBestSellerProductsByOrderProduct($best_seller_product_setting['limit']);

        $layout_module->setting = $best_seller_product_setting;

        return $layout_module;
    }

    /**
     * @param $layout_module
     * @return mixed
     */
    private function assemblePress(LayoutModule $layout_module)
    {
        $press_module = $layout_module->module;

        $press_setting = $press_module->setting;

        $press_setting['presses'] = $this->getPress($press_setting['limit']);

        $layout_module->setting = $press_setting;

        return $layout_module;
    }

    /**
     * @param $layout_module
     * @return mixed
     */
    private function assembleAppBlock(LayoutModule $layout_module)
    {
        $language_id = AppEnv::languageId();
        $app_block_module = $layout_module->module;

        $app_block_setting = $app_block_module->setting;
        $app_block_setting['language_id'] = $language_id;
        $app_block_setting['icons'] = $this->getAppBlock($app_block_setting['locale_icons_map'][$language_id]);

        unset($app_block_setting['locale_icons_map']);

        $layout_module->setting = $app_block_setting;

        return $layout_module;
    }

    /**
     * @param $locale_icons_map
     * @return mixed
     */
    public function getAppBlock($locale_icons_map)
    {
        $icons = [];

        foreach($locale_icons_map as $index => $locale_icon)
        {
            $icons[$index] = $locale_icon;
            $route = $locale_icon['image'];

            $icons[$index]['link'] = html_entity_decode($icons[$index]['link'], ENT_QUOTES, 'UTF-8');

            if ($route) {
                $icons[$index]['image'] = ImageHelper::generateImagePath($route);
            } else {
                $icons[$index]['image'] = null;
            }
        }

        return $icons;
    }


    /**
     * @see  \ModelCatalogProduct::getLatestProducts
     *
     * @param $limit
     * @return mixed
     * @throws \Exception
     */
    private function getLatestProduct($limit)
    {
        $latest_products = (new Product)
            ->filterOnShelf()
            ->with('productDescription',
                'productDiscounts',
                'productSpecials'
            )
            ->latest('date_added')
            ->select(['product_id', 'image', 'price'])
            ->limit($limit)
            ->get();

        $latest_products = $this->transformProducts($latest_products);

        return $latest_products;
    }

    /**
     * @param array $product_ids
     * @param int $limit
     *
     * @return \Illuminate\Support\Collection
     * @throws \Exception
     */
    public function getRecommendProduct(array $product_ids, int $limit)
    {
        $recommend_products = (new ProductRepository)
            ->queryFeaturedProducts($product_ids)
            ->limit($limit)
            ->get();

        $recommend_products = $this->transformProducts($recommend_products);

        return $recommend_products;
    }

    /**
     * @see \ModelCatalogProduct::getProductSpecials
     *
     * @param $limit
     * @return Collection|\Illuminate\Support\Collection
     * @throws \Exception
     */
    public function getSpecialProduct($limit)
    {
        /** @var LengthAwarePaginator|Collection $order_products */
        $specials_products = (new ProductRepository)
            ->querySpecialProducts()
            ->limit($limit ?: 5)
            ->get();

        $specials_products = $this->transformProducts($specials_products);

        return $specials_products;
    }

    /**
     * @param Collection $products
     * @return \Illuminate\Support\Collection
     * @throws \Exception
     */
    private function transformProducts(Collection $products)
    {
        /** @var Currency $currency */
        $currency = AppEnv::currency();

        $products = $products->map(function(Product $product) use($currency) {

//            $origin_price  = Product::getProductOriginPrice($product);
            $special_price  = $product->productSpecials->first()->price ?? null;

            return [
                'product_id'               => $product->product_id,
                'product_image'            => $product->origin_image,
                'product_name'             => $product->productDescription->name ?? null,
                'symbol_left'              => $currency->symbol_left,
                'symbol_right'             => $currency->symbol_right,
                'price'                    => $currency->exchangePrice($product->price),
                'special_price'            => $special_price ? $currency->exchangePrice($special_price) : null,
                'currency_settle_price'    => $currency->exchangePrice($product->settle_price),
            ];
        });

        return $products;
    }

    /**
     * @param $limit
     * @return mixed
     */
    private function getPress($limit)
    {
        $presses = (new Press)->where('status', Press::PRESS_STATUS_ON)
            ->whereHas('pressToStore', function (Builder $query) {
                $query->where('store_id', AppEnv::storeId());
            })
            ->with('filterPressDescriptionByLanguage')
            ->oldest('sort_order')
            ->latest('date_added')
            ->limit($limit)
            ->get();

        $presses->transform(function(Press $press){
            $press->title = $press->filterPressDescriptionByLanguage->title ?? null;
            $press->addHidden('filterPressDescriptionByLanguage');

            return $press;
        });

        return $presses;
    }

    /**
     * @deprecated (一个接口返回)
     * @see  \ModelCatalogProduct::getPopularProducts
     *
     * @param $limit
     * @return mixed
     */
    public function getPopularProducts($limit)
    {
        $popular_products = (new Product)->where('status', Product::PRODUCT_STATUS_ON)
            ->where('date_available', '<=', now())
            ->whereHas('productToStore', function(Builder $query){
                return $query->where('store_id', 0);
            })
            ->with('productDescription')
            ->latest('viewed', 'date_added')
            ->limit($limit)
            ->get();

        return $popular_products;
    }

    /**
     * @deprecated (废弃了！ 用下面的)
     * @see  \ModelCatalogProduct::getBestSellerProducts
     *
     * @param $language_id
     * @param $limit
     * @param $store_id
     * @return mixed
     * @throws \Exception
     */
    public function getBestSellerProducts($language_id, $limit, $store_id)
    {
        /** @var Collection $best_seller_products */
        $best_seller_products = (new Product)
            ->where('status', Product::PRODUCT_STATUS_ON)
            ->where('date_available', '<=', now())
            ->whereHas('productToStore', function(Builder $query) use($store_id) {
                return $query->where('store_id', $store_id);
            })
            ->has('bestSellerProducts')
            ->with('productDescription',
//                'filterProductDiscountByLatest',
//                'filterProductSpecialByLatest',
                'productDiscounts',
                'productSpecials',
//                'reviews',
                'bestSellerProducts'
                )
            ->select(['product_id', 'image', 'price'])
            ->get();

        $best_seller_products = $best_seller_products->map(function(Product $best_seller_product){
            $best_seller_product->selling_quantity = $best_seller_product->bestSellerProducts->sum('quantity');

            return $best_seller_product;
        })
            ->sortByDesc('selling_quantity')
            ->values()
            ->take($limit);

        $best_seller_products = $this->transformProducts($best_seller_products);

        return $best_seller_products;
    }

    /**
     * @see \ModelCatalogProduct::getBestSellerProducts
     *
     * @param $limit
     * @return Collection|\Illuminate\Support\Collection
     * @throws \Exception
     */
    public function getBestSellerProductsByOrderProduct($limit)
    {
        /** @var Collection $order_products */
        $order_products = (new ProductRepository)->queryBestSellerProducts(null, $limit ?: 5);

        $assemble_best_seller_products = $this->transformProducts($order_products);

        return $assemble_best_seller_products;
    }
}